<?php

require_once(SHMS_COMFAIR_PATH."/shms_comfair_constants.inc");
require_once(SHMS_CORE_PATH."/shms_core_common.inc");
require_once(SHMS_CORE_PATH."/shms_core_form_cca.inc");
require_once(SHMS_CORE_PATH."/shms_db_common.inc");

function shms_comfair_list($form,&$form_state){
  // field set -- select comfair | init comn fair
  // load current on going com fair
  require_once(SHMS_CORE_PATH."/shms_db_common.inc");
  
  // comfair list
  return $form;
}

/**
 * Either initiate or edit the current going com-fair. There's no point editing
 * an already-past com fair.
 */
function shms_comfair_init($form,&$form_state){
  $cf_query = db_select(SHMST_COMFAIR,'cf'); $cf_query->fields('cf');
  $cf_query->condition('year',shms_get_current_academic_year());
  $current_cf = $cf_query->execute()->fetchAssoc();
  $has_record = !empty($current_cf);
  $form = array(
    // year default to current
    'deadline'=> array(
      '#type' => 'date',
      '#title'=> t("Deadline"),
      '#description'  => t("The deadline for this com fair"),
      '#required' => TRUE,
    ),
    'submit'  => array(
      '#type' => 'submit',
      '#value'=> $has_record?t("Update"):t("Submit"),
      '#weight'=> 21,
    ),
  );
  
  // and then define participating coms
    // load groups of the defined|current academic year
  $query = db_select(SHMS_GROUP_TABLE,'g');
  $query->innerJoin(SHMS_GROUP_BY_YEAR_TABLE,'gy','gy.gid = g.id');
  if($has_record){
    $query->condition('gy.year',$current_cf['year']);
  } else{ 
    $query->condition('gy.year',shms_get_current_academic_year());
  }
  $query->addField('g','parent_gid');
  $query->fields('gy');
  $groups = $query->execute()->fetchAllAssoc('id',PDO::FETCH_ASSOC);
  
  // also load the base groups' names
  $pgroups = db_select(SHMS_GROUP_TABLE,'g')->condition("g.parent_gid",0)->fields("g")->execute()->fetchAllAssoc('id',PDO::FETCH_ASSOC);
  
  // build the fieldset for the groups under different subgroup
  $header = array("Name","Quota");
  $options_arr = array(); $gyid_to_p = array();
  foreach($groups as $group){
    if($group['parent_gid'] != 0){
      $options_arr[$group['parent_gid']][$group['id']] = array($group['name'],$group['quota']);
      $gyid_to_p[$group['id']] = $group['parent_gid'];  // build the gyid to parent_gid array
    }
  }
  foreach($options_arr as $pid => $options){
    $form[$pid] = array(
      '#type' => "fieldset",
      '#title'=> t($pgroups[$pid]['name']),
      '#description' => t("Groups participanting the com-fair"),
      
      'select'.$pid => array(
        '#type' => "tableselect",
        '#header'=> $header,
        '#options'=> $options,
      ),
    );
  }
  
  if($has_record){
    $option_default_val_arr = array();
    $query = db_select(SHMST_COMFAIR_IN_G,'cfg');
    $query->condition('cid',$current_cf['id']);
    $query->addField('cfg','gyid'); 
    $pref_g = $query->execute()->fetchCol();
    foreach($pref_g as $gyid){
      $option_default_val_arr[$gyid_to_p[$gyid]][$gyid] = $gyid;
    }
    
    $form['id'] = array('#type'=>'value','#value'=>$current_cf['id']);
    $form['deadline']['#default_value'] = shms_core_get_date_arr_from_timestamp($current_cf['deadline']);
    foreach($option_default_val_arr as $pgid => $default_arr){
      $form[$pgid]['select'.$pgid]['#default_value'] = $default_arr;
    }
  }
  return $form;
}

function shms_comfair_init_validate($form,&$form_state){
  $deadline_date = $form_state['values']['deadline'];
  $deadline = mktime(0,0,0,$deadline_date['month'],$deadline_date['day'],$deadline_date['year']);
  // TODO: check if within this academic year
  $form_state['values']['deadline'] = $deadline;
}

function shms_comfair_init_submit($form,&$form_state){
  // generate a new record of com fair
  @$id = $form_state['values']['id'];$deadline = $form_state['values']['deadline'];
  
  // com-fair basic
  if(isset($id)){ // update
    db_update(SHMST_COMFAIR)->condition('id',$id)->fields(array('deadline'=>$deadline))->execute();
    db_delete(SHMST_COMFAIR_IN_G)->condition('cid',$id)->execute();
    drupal_set_message("Com Fair has been updated.");
  } else{   // insert
    $id = 
      db_insert(SHMST_COMFAIR)->fields(array('year' => shms_get_current_academic_year(),
      'init_date' => time(), 'deadline' => $deadline ))->execute();
    drupal_set_message("Com Fair has been initialized.");
  }
  
  // then add in the group choices
  $res_arr = array();
  foreach($form_state['values'] as $key=>$value){
    if(substr($key, 0,6) != "select") continue;
    $res_arr += $value;
  }
  $res_arr = array_filter($res_arr);  // consists of an array of gid selected for the com fair
  $inQ = db_insert(SHMST_COMFAIR_IN_G); $inQ->fields(array("cid","gyid"));
  foreach($res_arr as $gyid){  // the selected gyid
    $inQ->values(array($id,$gyid));
  }
  $inQ->execute();
}

function shms_comfair_edit_get_title(){
  // check wheter a common fair has been init
  $res = db_select(SHMST_COMFAIR,'cf')->fields('cf')->condition('year',shms_get_current_academic_year())->execute()->fetchAssoc();
  return (empty($res)?"Init":"Edit")." Com Fair";
}

function shms_comfair_rank_group($form,&$form_state,$cid,$pyid){
  // only the person itself can do this
  // get pid from pyid
  $py_record = shms_core_db_load_from_table(SHMS_PERSON_BY_YEAR_TABLE, 'id', $pyid);
  if(!shms_validate_person_is_user(NULL,$py_record['pid'])){
    drupal_set_message("Sorry You don't have access to this page.","error");
    return array();
  }
  
  // load the group into the COM Fair, once would be enough
  if(!isset($form_state['storage']))  $form_state['storage'] = array();
  $storage = &$form_state['storage'];
  // load current settings if already done
  if(!isset($storage['old_pref'])){
    $storage['old'] = db_select(SHMST_COMFAIR_PPREF_RANK,"cpr")->condition('cid',$cid)
      ->condition('pyid',$pyid)->fields("cpr",array('gyid','rank'))
      ->execute()->fetchAllKeyed();
    $storage['old_pref'] = db_select(SHMST_COMFAIR_PPREF,"cp")->condition('cid',$cid)
      ->condition('pyid',$pyid)->fields("cp",array())->execute()->fetchAssoc();
  }
  if(!isset($storage['groups'])){
    $query = db_select(SHMST_COMFAIR_IN_G,'gp'); $query->addField('gp','gyid'); 
    $query->innerJoin(SHMS_GROUP_BY_YEAR_TABLE,"gy",'gy.id = gp.gyid');
    $query->addField('gy','name'); $query->condition('gp.cid',$cid);
    $groups_to_save = $query->execute()->fetchAllKeyed();
    
    // but filter out the groups this person is currently in
      // the line below would get all groups (including history) this person has
      // been in. But the extra group would not affect the result cuz they're not
      // in the set to be unset
    $current_in_group = db_select(SHMS_PERSON_GROUP_TABLE,"pg")
      ->condition("pyid",$pyid)->fields("pg",array("gyid"))->execute()->fetchCol();
    foreach($current_in_group as $gyid){
      if(isset($groups_to_save[$gyid])) unset($groups_to_save[$gyid]);
    }
    
    $storage['groups'] = $groups_to_save;
  }
  
  $groups = $storage['groups'];
  if(!isset($storage['step']))  $storage['step'] = "define"; // define and rank
  $step = $storage['step'];
  $storage['cid'] = $cid; $storage['pyid'] = $pyid;
  
  if($step == "define"){
    // take the list of groups as options
    $form['choose_group'] = array(
      '#title'  => t("Groups to Join"),
      '#type'   => "checkboxes",
      '#options'=> $groups,
      '#required' => TRUE,
      '#description'=> t("The groups you're already in has been filtered out already. You may come ".
        l("here","cca/my",array('attributes'=>array("target"=>"_blank")))." to see your current CCAs.")
    );
    $form['max_num'] = array(
      '#title'  => t("Maximum number of groups you want to join"),
      '#type'   => "textfield",
      '#element_validate' => array("shms_core_form_validate_int_field"),
      '#required' => TRUE,
    );
    
    if($storage['old_pref']){  // if this step exist, it's update therefore add in the default value
      // get the default value from the rank of groups
      $selected_groups = array();
      foreach($storage['old'] as $gyid=>$rank){
        $selected_groups[$gyid] = $gyid;
      }
      $form['choose_group']['#default_value'] = $selected_groups;
      $form['max_num']['#default_value'] = $storage['old_pref']['maximum_g'];
    }
  } else if($step == "rank"){ // this form would function both as a rank, and as a 
    $count = 1; $select_opt = array();  // TODO: set a starting rank for the "count"
    $form['groups']['#tree']  = TRUE;
    foreach($groups as $gyid=>$gname){
      $select_opt[$count] = $count;
      $form['groups'][$gyid] = array(
        'name'  => array( '#markup' => $gname),
        'rank'=> array(
          '#type' => 'select',
          '#disabled' => TRUE,
          '#default_value'  => $count++,
        ),
      );
    }
    foreach($groups as $gyid=>$gname){
      $form['groups'][$gyid]['rank']['#options'] = $select_opt;
    }
    
    $form['groups']['#theme'] = "shms_selectable_table";
  }
  
  $form['submit'] = array(
    '#type' => "submit",
    '#value'=> t("Submit"),
  );
  
  return $form;
}


function shms_comfair_rank_group_validate($form,&$form_state){
  
}

function shms_comfair_rank_group_submit($form,&$form_state){
  $storage = &$form_state['storage'];
  $cid = $storage['cid']; $pyid = $storage['pyid'];
  if($storage['step'] == "define"){
    $storage['step'] = "rank";
    $form_state['rebuild']  = TRUE;
    $storage['groups'] = array_intersect_key($storage['groups'],array_filter($form_state['values']['choose_group']));
    $storage['max_num'] = $form_state['values']['max_num'];
    $form_state['rebuild']  = TRUE;
  } else if($storage['step'] == "rank"){
    $ts = db_transaction();
    try{
      // remove the old data if exist
      db_delete(SHMST_COMFAIR_PPREF)->condition('cid',$cid)->condition('pyid',$pyid)->execute();
      db_delete(SHMST_COMFAIR_PPREF_RANK)->condition('cid',$cid)->condition('pyid',$pyid)->execute();
      
      // store the data internally
      db_insert(SHMST_COMFAIR_PPREF)->fields(array('cid'=>$cid,'pyid'=>$pyid,'maximum_g'=>$storage['max_num']))->execute();
      
      // save the group ranking
      $insertQ = db_insert(SHMST_COMFAIR_PPREF_RANK)->fields(array('cid','pyid','gyid','rank'));
      foreach($form_state['values']['groups'] as $gyid=>$record){
        $insertQ->values(array($cid,$pyid,$gyid,$record['rank']));
      }
      $insertQ->execute();
    } catch(exception $e){
      drupal_set_message("Sorry some error occured. You may contact the site admin for help.","error");
      watchdog("error",$e->__toString());
    }
    drupal_set_message("Thanks, your preference has been saved.");
  }
}

/**
 * Multi-step form. Which needs:
 * 1. select potential list of person
 * 2. randomize the list, ask the chair person to rank
 */
function shms_comfair_rank_person($form,&$form_state,$cid,$gyid){
  // only the chair person can do this
  require_once(SHMS_CORE_PATH."/shms_core_form_cca.inc");
  if(!shms_cca_form_verify_user_access($form_state,$gyid)){
    drupal_set_message("Sorry You don't have access to this page.","error");
    return array();
  }
  
  // save the id first
  if(!isset($form_state['storage'])) $form_state['storage'] = array();
  $storage = &$form_state['storage'];
  if(!isset($storage['cid'])){
    $storage['cid'] = $cid; $storage['gyid'] = $gyid;
    // load the list of current residence
    require_once(SHMS_CORE_PATH."/shms_db_common.inc");
    $storage['plist'] = shms_comfair_group_load_residence_list($gyid);
    $storage['group'] = shms_core_db_load_from_table(SHMS_GROUP_BY_YEAR_TABLE, 'id', $gyid);
    $storage['maximum_num'] = $storage['group']['quota'] * 2;
  }
  if(!isset($storage['step'])) $storage['step'] = 'select';
  
  $plist = $storage['plist'];
  $quota200 = $storage['maximum_num'];
  
  if($storage['step'] == 'select'){
    // load the current list as selected
    $current_list = db_select(SHMST_COMFAIR_GPREF_RANK,"gr")->condition("cid",$cid)
      ->condition("gyid",$gyid)->fields("gr",array('pyid'))->execute()->fetchCol();
    
    $form['info'] = array('#markup'=>t("<strong>Please select up to :num people.</strong>",array(':num'=>$quota200)));
    
    // TODO: add in a counter here. later when the problem with check box is fixed.
    // " Currently <span id='empty-slot-left-cnt'>x</span> people to be selected.",array(':num'=>$group['quota'])));
    // drupal_add_js(SHMS_COMFAIR_PATH."/shms_comfair_form.js");
    
    $header = array("Full Name","Matric No.","Room Number"); $blkRows = array();
    $list_default_arr = array();
    // build the residence list array
    foreach ($plist as $pid => $record) {
      $blk_letter = $record['room_number']{0}; $ppyid = $record['pyid'];
      $blkRows[$blk_letter][$ppyid] = array(
        $record['full_name'],$record['matric_no'],$record['room_number'],
      );
      if(in_array($ppyid, $current_list)){
        $list_default_arr[$blk_letter][$ppyid] = $ppyid;
      }
    }
    ksort($blkRows);
    foreach($blkRows as $blk_letter => $rows){
      $form[$blk_letter] = array(
        '#type' => "fieldset",
        '#title'=> t("Block ".$blk_letter),
        '#collapsible'  => TRUE,
        '#collapsed'    => FALSE,
        'person'.$blk_letter => array(
          '#type' => "tableselect",
          '#header' => $header,
          "#options"=> $rows,
          '#default_value' => isset($list_default_arr[$blk_letter])?$list_default_arr[$blk_letter]:array(),
          '#empty' => t("Sorry There's no residence in this block yet as in the record."),
        ),
      );
    }
  } else if($storage['step'] == "rank"){
    $count = 1; $select_opt = array();  // TODO: set a starting rank for the "count"
    $form['people']['#tree']  = TRUE;
    shuffle($plist);
    foreach($plist as $record){
      $pyid = $record['pyid'];
      $select_opt[$count] = $count;
      $form['people'][$pyid] = array(
        'name'  => array( '#markup' => $record['full_name']."\t(".$record['room_number'].")"),
        'rank'=> array(
          '#type' => 'select',
          '#disabled' => TRUE,
          '#default_value'  => $count++,
        ),
      );
    }
    foreach($plist as $record){
      $pyid = $record['pyid'];
      $form['people'][$pyid]['rank']['#options'] = $select_opt;
    }
    $form['people']['#theme'] = "shms_selectable_table";
  }
    
  $form['submit'] = array(
    '#type' => "submit",
    '#value'=> t("Submit"),
  );
    
  return $form;
}

function shms_comfair_rank_person_validate($form,&$form_state){
  // validate the number of residences selected
  if($form_state['storage']['step'] == 'select'){
    // and build the update array
    $person_arr = array();
    foreach($form_state['values'] as $key=>$value){
      if(preg_match("/^person[A-E]$/", $key)) $person_arr += array_filter($value);
    }
    $selected_cnt = sizeof($person_arr);
    $form_state['storage']['person_arr'] = $person_arr;
    if($selected_cnt > $form_state['storage']['maximum_num']){
      form_set_error("nothing","Total number of people exceeded the allowed quota.");
    } else if($selected_cnt == 0){
      form_set_error("nothing","Sorry you need to select someone at least.");
    }
  }
}

function shms_comfair_rank_person_submit($form,&$form_state){
  $storage = &$form_state['storage'];
  $cid = $storage['cid']; $gyid = $storage['gyid'];
  
  if($storage['step'] == 'select'){
    $storage['step'] = 'rank';
    foreach(array_keys($storage['plist']) as $pyid){
      if(!array_key_exists($pyid, $storage['person_arr'])){
        unset($storage['plist'][$pyid]);
      }
    }
    $form_state['rebuild'] = TRUE;
  } else if($storage['step'] == 'rank'){
    $ts = db_transaction();
    try{
      // remove the old data if exist
      db_delete(SHMST_COMFAIR_GPREF_RANK)->condition('cid',$cid)->condition('gyid',$gyid)->execute();
      
      // save the group ranking
      $insertQ = db_insert(SHMST_COMFAIR_GPREF_RANK)->fields(array('cid','pyid','gyid','rank'));
      foreach($form_state['values']['people'] as $pyid=>$record){
        $insertQ->values(array($cid,$pyid,$gyid,$record['rank']));
      }
      $insertQ->execute();
    } catch(exception $e){
      drupal_set_message("Sorry some error occured. You may contact the site admin for help.","error");
      watchdog("error",$e->__toString());
    }
    drupal_set_message("Thanks, your preference has been saved.");
  }
}


function shms_comfair_group_load_residence_list($gyid){
  require_once(SHMS_CORE_PATH."/shms_db_common.inc");
  
  // all residence
  $plist = shms_core_db_load_persons_by_blk("all","pyid");
  
  // filter out the president
  $chair_pyid_q = db_select(SHMS_GROUP_BY_YEAR_TABLE,"gy");
  $chair_pyid_q->condition("gy.id",$gyid);
  $chair_pyid_q->innerJoin(SHMS_PERSON_BY_YEAR_TABLE,"py","gy.chair_pid = py.id AND gy.year = py.year");
  $chair_pyid_q->addField("py","id");
  $chair_pyid = $chair_pyid_q->execute()->fetchCol();
  $chair_pyid = array_shift($chair_pyid);  // there's only 1 record
  unset($plist[$chair_pyid]);
  
  // filter out the already existing members
  $current_memebrs_q = db_select(SHMS_PERSON_GROUP_TABLE,"pg");
  $current_memebrs_q->condition("pg.gyid",$gyid);
  $current_memebrs_q->fields("pg",array("id"));
  $current_memebrs = $current_memebrs_q->execute()->fetchCol();
  
  foreach($current_memebrs as $pyid){
    unset($plist[$pyid]);
  }
  
  return $plist;
}

/**
 * select the "exclude-form"
 */
function shms_comfair_exclude_person($form,&$form_state,$cid,$gyid){
  if(!shms_cca_form_verify_user_access($form_state,$gyid)){
    drupal_set_message("Sorry You don't have access to this page.","error");
    return array();
  }
  
  // save the id first
  if(!isset($form_state['storage'])) $form_state['storage'] = array();
  $storage = &$form_state['storage'];
  $storage['cid'] = $cid; $storage['gyid'] = $gyid;
  
  // load the list of current residence
  $plist = shms_comfair_group_load_residence_list($gyid);
  
  // exclude existing members.
  
  // and load the current list as selected
  $current_list = db_select(SHMST_COMFAIR_GPREF_EXCLUDE,"ge")->condition("cid",$cid)
    ->condition("gyid",$gyid)->fields("ge",array('pyid'))->execute()->fetchCol();
  
  $form['info'] = array('#markup'=>t("<strong>Note: The following list of people would be".
      " excluded form your committee.</strong>"));
  
  $header = array("Full Name","Matric No.","Room Number"); $blkRows = array();
  $list_default_arr = array();
  // build the residence list array
  foreach ($plist as $pid => $record) {
    $blk_letter = $record['room_number']{0}; $ppyid = $record['pyid'];
    $blkRows[$blk_letter][$ppyid] = array(
      $record['full_name'],$record['matric_no'],$record['room_number'],
    );
    if(in_array($ppyid, $current_list)){
      $list_default_arr[$blk_letter][$ppyid] = $ppyid;
    }
  }
  ksort($blkRows);
  foreach($blkRows as $blk_letter => $rows){
    $form[$blk_letter] = array(
      '#type' => "fieldset",
      '#title'=> t("Block ".$blk_letter),
      '#collapsible'  => TRUE,
      '#collapsed'    => FALSE,
      'person'.$blk_letter => array(
        '#type' => "tableselect",
        '#header' => $header,
        "#options"=> $rows,
        '#default_value' => isset($list_default_arr[$blk_letter])?$list_default_arr[$blk_letter]:array(),
        '#empty' => t("Sorry There's no residence in this block yet as in the record."),
      ),
    );
  }
  
  $form['submit'] = array(
    '#type' => "submit",
    '#value'=> t("Submit"),
  );
  return $form;
}


function shms_comfair_exclude_person_submit($form,&$form_state){
  $storage = $form_state['storage'];
  $cid = $storage['cid']; $gyid = $storage['gyid'];
  
  $ts = db_transaction();
  try{
    // first remove all the old records
    db_delete(SHMST_COMFAIR_GPREF_EXCLUDE)->condition('cid',$cid)->condition('gyid',$gyid)->execute();
    
    // and build the update array
    $person_arr = array();
    foreach($form_state['values'] as $key=>$value){
      if(preg_match("/^person[A-E]$/", $key)) $person_arr += array_filter($value);
    }
    
    $person_cnt = 0; $names = array();
    $insertQ = db_insert(SHMST_COMFAIR_GPREF_EXCLUDE)->fields(array('cid','gyid','pyid'));
    foreach($person_arr as $pyid){
      $insertQ->values(array($cid,$gyid,$pyid));
      $person_cnt++; $names[] = $form_state['storage']['plist'][$pyid]['full_name'];
    }
    $insertQ->execute();
    drupal_set_message("$person_cnt people has been exclued from your CCA: ".implode(",", $names));
  } catch(exception $e){
    watchdog("error", $e->__toString());
    drupal_set_message("Sorry Error Occured. You may contact the site admin for help.","error");
  }
}

function theme_shms_selectable_table($variable){
  $form = $variable['form'];
  $table_rows = array(); 
  foreach(element_children($form) as $id){
    $form[$id]['rank']['#attributes']['class'] = array('example-item-weight');
    $table_rows[] = array(
      'data'  => array(
        drupal_render($form[$id]['name']),
        drupal_render($form[$id]['rank'])
      ),
      'class' => array('draggable'),
    );
  }
  $table_header = array(t("Name"),t("Rank"));
  $table_id = "groups_table";
  $output = "";
  $output .= theme('table', array('header'=>$table_header, 'rows'=>$table_rows, 'attributes'=>array('id' => $table_id)));
  $output .= drupal_render_children($form);
  drupal_add_tabledrag($table_id, 'order', 'sibling', 'example-item-weight',NULL,NULL,FALSE); 
  return $output;
}

/**
 * Get the result for the comfair, of who is going to where.
 * 
 * Algorithm:
 * 1. people's first choice would be fulfilled, based on random order.
 *    coms would be filled with people in random order, until it's full
 * 2. if coms still got open space, go select the people, who also selected 
 *    this comn and haven't exceed its maximum prefered comns yet, in comns' 
 *    preference list, in the order of preference.
 * 3. download the thing as excel
 */
function shms_comfair_get_result($form,&$form_state,$cfid){
  // people's preference on comns
  $people_max_com_num = db_select(SHMST_COMFAIR_PPREF,"cfp")
    ->condition("cid",$cfid)->fields('cfp',array("pyid","maximum_g"))->execute()->fetchAllKeyed();
  $people_pref_res = db_select(SHMST_COMFAIR_PPREF_RANK,"pr")->condition("cid",$cfid)
    ->fields("pr",array("id","pyid","gyid","rank"))->execute();
  $people_pref_list = array();
  while($people_pref_record = $people_pref_res->fetchAssoc()){
    $people_pref_list[$people_pref_record['pyid']][$people_pref_record['rank']]
      = $people_pref_record['gyid'];
  }
  // group's pref on people
    // exclude list
  $group_exclude_res = db_select(SHMST_COMFAIR_GPREF_EXCLUDE,"ge")->condition("cid",$cfid)->fields("ge",array())->execute();
  $group_exclude_list = array();
  while($group_exc_record = $group_exclude_res->fetchAssoc()){
    $group_exclude_list[$group_exc_record['gyid']][] = $group_exc_record['pyid'];
  }
    // preference list
  $group_rank_res = db_select(SHMST_COMFAIR_GPREF_RANK,"gr")->condition("cid",$cfid)->fields("gr",array())->execute();
  $group_rank_list = array();
  while($group_rank_record = $group_rank_res->fetchAssoc()){
    $group_rank_list[$group_rank_record['gyid']][$group_rank_record['rank']] = $group_rank_record['pyid'];
  }
      
  // basic preparation
    // pyid indexed array, to provide person name info
  $people_info_arr_q =  db_select(SHMS_PERSON_TABLE,"p");
  $people_info_arr_q->innerJoin(SHMS_PERSON_BY_YEAR_TABLE,"py",'py.pid = p.id');
  $people_info_arr_q->condition("py.year",shms_get_current_academic_year());
  $people_info_arr_q->fields("p",array("full_name","matric_no"));
  $people_info_arr_q->fields("py",array("id","pid","room_number"));
  $people_info_arr = $people_info_arr_q->execute()->fetchAllAssoc("id",PDO::FETCH_ASSOC);
    // gy indexed array, to provide group name info
  $group_info_arr = db_select(SHMS_GROUP_BY_YEAR_TABLE,"gy")->condition("year",shms_get_current_academic_year())
      ->fields("gy",array())->execute()->fetchAllAssoc("id",PDO::FETCH_ASSOC);
      
  // load the current group member
  $group_current_members_ld = db_select(SHMS_PERSON_GROUP_TABLE,"pg");
  $group_current_members_ld->innerJoin(SHMS_GROUP_BY_YEAR_TABLE,"gy","gy.id = pg.gyid");
  $group_current_members_ld->condition("gy.year",shms_get_current_academic_year());
  $group_current_members_ld->fields('pg', array('id','pyid','gyid'));
  $group_current_members_lst = $group_current_members_ld->execute()->fetchAllAssoc("id",PDO::FETCH_ASSOC);
  $group_current_members = array();
  foreach($group_current_members_lst as $record){
    $group_current_members[$record['pyid']][] = $record['gyid'];
  }
      
      // ready to run the algorithm now :)
/*
 * 1. people's first choice would be fulfilled, based on random order.
 *    coms would be filled with people in random order, until it's full
 * 2. if coms still got open space, go select the people, who also selected 
 *    this comn and haven't exceed its maximum prefered comns yet, in comns' 
 *    preference list, in the order of preference.
 * 3. download the thing as excel
 */
  $people_groups = array();
  foreach($group_current_members as $gyid => $lst){
    foreach($lst as $pyid){
      $people_groups[$pyid][] = $gyid;
    }
  }

  // load current group config into group_members, and save in person_groups table 
  // correspondingly
  $group_members = $group_current_members;
  
  // assign the first rank.
  // it's possible that people has already been assigned with a com
  $filtered_arr = array_filter($people_pref_list,"_shms_comfair_array_has_rank_1");
  $plist_random = array_keys($filtered_arr);
  shuffle($plist_random);
  foreach($plist_random as $pyid){
    // print("processing person $pyid now.\n");
    if($people_max_com_num[$pyid] <= sizeof($people_groups[$pyid])){  // if the people has full joined.
      // print("person with id $pyid don't want to join any\n");
      continue; // if the person do not want to join any
    }
    $prefered_group_gyid = $people_pref_list[$pyid][1];
     // if excluded by group then simply skip
    if(isset($group_exclude_list[$prefered_group_gyid]) && in_array($pyid, $group_exclude_list[$prefered_group_gyid])){
      // print("person $pyid exclueded by group $prefered_group_gyid \n");
      continue;
    }
    if(isset($group_members[$prefered_group_gyid]) &&  // if the group is full
      (sizeof($group_members[$prefered_group_gyid]) >= $group_info_arr[$prefered_group_gyid]['quota'])) continue;
    
    // excluded all possible problem already... now do the assigning.
    $group_members[$prefered_group_gyid][] = $pyid;
    $people_groups[$pyid][] = $prefered_group_gyid;
  }
  
  // get a list of groups which haven't exceeded their quota yet
  $groups_to_fill = array_keys($group_rank_list);
    // filter out the already_full groups
  $groups_to_remove = array();
  foreach($groups_to_fill as $key => $gyid){
    if(isset($group_members[$gyid]) &&
       (sizeof($group_members[$gyid]) >= $group_info_arr[$gyid]['quota'])){
        $groups_to_remove[] = $key;
        //printf("group id: %d, quota %d, current member size: %d\n",$gyid,$group_info_arr[$gyid]['quota'],sizeof($group_members[$gyid]));
    }
  }
  foreach($groups_to_remove as $key) unset($groups_to_fill[$key]);

  // starting by checking rank 2
  $groups_processing_rank = array_fill_keys($groups_to_fill, 2);  

  // now check the groups according to their preferred list of people
  $has_changed = TRUE;
  while(!empty($groups_to_fill) && $has_changed){  // run as long as got group unassigned.
    $has_changed = FALSE;  // would remark it as true whenever there's any group info
    // loop through the groups once and assign
    shuffle($groups_to_fill); // each time shuffle to keep fairness
    $groups_to_remove = array();
    foreach($groups_to_fill as $key=>$gyid){
      // try fill one member according to groups's and person's willingness: in the order of group's rank,
      // select the people which also selected the group, even if it's in the group's exclude list.
      //    (cuz group selected the person in the first place.)
      
      // proceed the groups's rank list by 1 each time;
      // but in the case person being selected already, proceed by 1 another time, until person is selected.
      while($groups_processing_rank[$gyid] <= sizeof($group_rank_list[$gyid])){
        $consider_pyid = $group_rank_list[$gyid][$groups_processing_rank[$gyid]++]; // auto proceed
        if(!in_array($consider_pyid,$group_members[$gyid])  // non in that group yet
          && sizeof($people_groups[$consider_pyid]) < $people_max_com_num[$consider_pyid] // strictly less
        ){ // would fill it
          $people_groups[$consider_pyid][] = $gyid;
          $group_members[$gyid][] = $consider_pyid;
          $has_changed = TRUE; // 
          break;
        }
      }
      if(sizeof($group_members[$gyid]) >= $group_info_arr[$gyid]['quota']){
        $groups_to_remove[] = $key;
      }
    }

    // then remove the already filled groups
    foreach($groups_to_remove as $key)  unset($groups_to_fill[$key]);
  }

  // then present the result
  $output_res = "People's maximum groups\n".print_r($people_max_com_num,TRUE).
    "Groups to fill arr: \n".print_r($groups_to_fill,TRUE).
    "\nPerson in group: \n". print_r($people_groups,TRUE).
    "\nGroup's Member:\n". print_r($group_members,TRUE);
  // TODO: support to download it as excel
  drupal_set_message("<pre>".print_r($output_res,TRUE)."</pre>","error");
  
  return $form;
}

function _shms_comfair_array_has_rank_1($arr){
  return array_key_exists(1, $arr);
}
